package com.pan.service.impl;

import com.pan.config.common.SeckillRabbitmqCommon;
import com.pan.dao.coupon.CouponSelectDao;
import com.pan.dao.couponHistory.CouponHistoryDao;
import com.pan.dao.seckillCouponResult.SeckillCouponResultDao;
import com.pan.dao.seckillCouponResult.SeckillCouponResultSelectDao;
import com.pan.entity.Coupon;
import com.pan.entity.CouponHistory;
import com.pan.entity.Result;
import com.pan.entity.SeckillCouponResult;
import com.pan.enume.ResultEnum;
import com.pan.excep.enume.ErrorCode;
import com.pan.feign.UserServerClient;
import com.pan.feign.vo.UserVo;
import com.pan.service.SeckillCouponListener;
import com.pan.tools.ConvertObject;
import com.pan.tools.RedisTools;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;


@Service("seckillCouponListener")
@RabbitListener(queues = {SeckillRabbitmqCommon.RABBITMQ_SECKILL_COUPON_TOPIC})
public class SeckillCouponListenerImpl implements SeckillCouponListener {

    @Resource
    private RedisTools redisTools;

    @Resource
    private CouponSelectDao couponSelectDao;

    @Resource
    private CouponHistoryDao couponHistoryDao;

    @Resource
    private UserServerClient userServerClient;

    @Resource
    private SeckillCouponResultDao seckillCouponResultDao;

    @Resource
    private SeckillCouponResultSelectDao seckillCouponResultSelectDao;


    public Result<List<SeckillCouponResult>> selectSeckillCouponResultByUserId(String userTicket){
        Result<Object> userIdResult = redisTools.hget("user:"+userTicket,"id");
        Long userId = (Long) userIdResult.getData();
        if (userId==null){
            return new Result(ResultEnum.USER_NOT_FOUND_ERROR);
        }
        List<SeckillCouponResult> li = seckillCouponResultSelectDao.selectByUserId(userId);
        li.stream().sorted(Comparator.comparing(SeckillCouponResult::getOperationTime).reversed()).collect(Collectors.toList());
        Result<List<SeckillCouponResult>> result = new Result<>(ResultEnum.SUCCESS,li);
        return result;
    }


    public SeckillCouponResult mappingResult(SeckillCouponResult seckillCouponResult,Map map){
        Map<String,Field> fieldMap = Arrays.stream(SeckillCouponResult.class.getDeclaredFields())
                .collect(Collectors.toMap(Field::getName,field -> field));
        Iterator<Map.Entry<String,Object>> iterator = map.entrySet().iterator();
        while (iterator.hasNext()){
            Map.Entry<String,Object> entry = iterator.next();
            Field field = fieldMap.get(entry.getKey());
            if (field == null){
                continue;
            }
            field.setAccessible(true);
            try {
                field.set(seckillCouponResult,entry.getValue());
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
        return seckillCouponResult;
    }

    public SeckillCouponResult getSeckillCouponResult(Result result,Map rabbitMap){

        SeckillCouponResult seckillCouponResult = new SeckillCouponResult();
        seckillCouponResult = ConvertObject.convertObject(seckillCouponResult,result);
        seckillCouponResult = mappingResult(seckillCouponResult,rabbitMap);
        Timestamp nowTime = new Timestamp(System.currentTimeMillis());
        seckillCouponResult.setOperationTime(nowTime);

        String userTicket = (String) rabbitMap.get("userTicket");
        Long userId = Long.parseLong((String) redisTools.hget("user:"+userTicket,"id").getData());
        seckillCouponResult.setUserId(userId);


        Timestamp seckillTime = (Timestamp) rabbitMap.get("seckillTime");
        seckillCouponResult.setSeckillTime(seckillTime);
        return seckillCouponResult;
    }

    /**
     //    rabbitmq 消息队列传过来的数据
     //    map:
     //          seckillTime:
     //          userTicket:
     //          couponId:
     -----------------------------
     */
    @RabbitHandler
//    @GlobalTransactional
    public void process(Map map) throws NoSuchFieldException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {
        String userTicket = (String) map.get("userTicket");
        Long couponId = (Long) map.get("couponId");
        Long userId = Long.parseLong((String) redisTools.hget("user:"+userTicket,"id").getData());
        Coupon coupon = couponSelectDao.selectById(couponId);

        if (coupon == null){
            Result result = new Result(ErrorCode.NOT_FOUND);
            SeckillCouponResult  seckillCouponResult = getSeckillCouponResult(result,map);
            seckillCouponResultDao.insert(seckillCouponResult);
            return;
        }
        Integer publishCount = coupon.getPublishCount();
        Integer receiveCount = coupon.getReceiveCount();
        if (publishCount == receiveCount){
            Result result = new Result(403,"该优惠券已经领取完");
            SeckillCouponResult  seckillCouponResult = getSeckillCouponResult(result,map);
            seckillCouponResultDao.insert(seckillCouponResult);
            return;
        }
        if (System.currentTimeMillis() > coupon.getEndDate().getTime()){
            Result result = new Result(403,"该优惠券已经过期");
            SeckillCouponResult  seckillCouponResult = getSeckillCouponResult(result,map);
            seckillCouponResultDao.insert(seckillCouponResult);
            return;
        }
        if (System.currentTimeMillis() < coupon.getStartDate().getTime()){
            Result result = new Result(403,"该优惠券未开始领取");
            SeckillCouponResult  seckillCouponResult = getSeckillCouponResult(result,map);
            seckillCouponResultDao.insert(seckillCouponResult);
            return;
        }
        Integer userReceiveCount = couponHistoryDao.selectCountByCouponIdAndUserId(userId,couponId);
        Integer userLimit = coupon.getUserLimit();
        if (userLimit != -1 && userLimit<=userReceiveCount){
            Result result = new Result(403,"用户已经领完该优惠券");
            SeckillCouponResult  seckillCouponResult = getSeckillCouponResult(result,map);
            seckillCouponResultDao.insert(seckillCouponResult);
            return;
        }
        Result<UserVo> userVoResult= userServerClient.selectById(userId);
        UserVo userVo = userVoResult.getData();
        Long balance = userVo.getScore() - new Long(coupon.getScorePrice());
        if (balance < 0){
            Result result = new Result(403,"账户积分不足");
            SeckillCouponResult  seckillCouponResult = getSeckillCouponResult(result,map);
            seckillCouponResultDao.insert(seckillCouponResult);
            return;
        }
        Result isReceive = userServerClient.updateNoCookie(userTicket,"score",balance);
        if (isReceive.getCode()!=200){
            Result result = new Result(500,"扣除积分失败");
            SeckillCouponResult  seckillCouponResult = getSeckillCouponResult(result,map);

            seckillCouponResultDao.insert(seckillCouponResult);
            return;
        }
        CouponHistory couponHistory = new CouponHistory();
        couponHistory.setCouponId(couponId).setUserId(userId)
                .setCreateDate(new Timestamp(System.currentTimeMillis()))
                .setUseType(0).setOrderId(null).setUseDate(null);
        Long couponHistoryId = couponHistoryDao.insert(couponHistory);
        Result result = new Result(200,"成功:"+couponHistoryId);
        SeckillCouponResult  seckillCouponResult = getSeckillCouponResult(result,map);
        seckillCouponResultDao.insert(seckillCouponResult);
        return;
    }


}
